<html>
  <head>
    <title>
      abp内置分布式事件
    </title>
  </head>
  <body>
    <script>
       /*
                        五、预定义分布式事件

                                  一旦你对实体进行配置，ABP会自动为 创建、更新、删除 等操作发布分布式事件。
                                  
                                  1、预定义分布式事件类型：

                                                    有三种预定义的分布式事件类型：
                                                                
                                                            ①、EntityCreatedEto<T>在创建类型为T的实体时发布。

                                                            ②、EntityUpdatedEto<T>在更新类型为T的实体时发布。

                                                            ③、EntityDeletedEto<T>在删除类型为T的实体时发布。

                                            这些事件类型是泛型的。 T 实际上是 EventTransferObjec (ETO)的类型，而不是实体的类型。
                                            因为，实体对象不能作为事件数据的一部分进行传输。
                                            因此，通常为实体类定义一个ETO类，如 Product实体的 ProductEto


                                   2、订阅预定义分布式事件

                                           订阅自动事件与订阅常规分布式事件相同。
                                           
                                           eg: 一旦产品更新，就会收到通知：

                                                using System.Threading.Tasks;
                                                using Volo.Abp.DependencyInjection;
                                                using Volo.Abp.Domain.Entities.Events.Distributed;
                                                using Volo.Abp.EventBus.Distributed;

                                                namespace AbpDemo
                                                {
                                                    public class MyHandler : 
                                                        IDistributedEventHandler<EntityUpdatedEto<ProductEto>>, // 订阅分布式实体更新事件
                                                        ITransientDependency
                                                    {
                                                        // 分布式事件处理逻辑
                                                        public async Task HandleEventAsync(EntityUpdatedEto<ProductEto> eventData)
                                                        {
                                                            var productId = eventData.Entity.Id;
                                                            //TODO
                                                        }
                                                    }
                                                }

                                            MyHandler实现了IDistributedEventHandler<EntityUpdatedEto<ProductEto>>。
                                            
                                            需要将处理程序类注册到依赖注入系统。像在本例中一样实现ITransientDependency是一种简单的方法。


                                   3、配置预定义分布式事件系统 （哪些实体需要发布分布式事件?需要在模块类中配置）

                                            你可以在模块的ConfigureServices中配置 "AbpDistributedEntityEventOptions" 以添加选择器。

                                            eg:  
                                                Configure<AbpDistributedEntityEventOptions>(options =>
                                                {
                                                    // 所有实体都发布"实体分布式事件"
                                                    options.AutoEventSelectors.AddAll();

                                                    // 指定单个实体发布"实体分布式事件"
                                                    options.AutoEventSelectors.Add<Product>();

                                                    // 指定某个命名空间下的所有实体发布"实体分布式事件"
                                                    options.AutoEventSelectors.AddNamespace("MyProject.Products");

                                                    // 通过lambda表达式操作反射来添加选择器，自定义过滤逻辑
                                                    options.AutoEventSelectors.Add(
                                                        type => type.Namespace.StartsWith("MyProject.")
                                                    );
                                                });

                                                最后一个提供了灵活性来决定是否应为给定实体类型发布事件。返回true以接受Type。

                                                你可以添加多个选择器。如果其中一个选择器与实体类型匹配，则选择它。

                                                也就是说选择器与选择器之间是 "或" 的关系。

                                    
                                    4、事件传输多想  Eto

                                             为实体启用"自动分布式事件"后， ABP开始发布有关实体更改的事件。

                                             此时，如果你没有为实体指定相应的 EventTransferObject (Eto)，则ABP会使用名为 EntityEto的标准类型，

                                             名为"EntityEto"的标准类型有两个属性：
                                                        
                                                        ①、EntityType（string）：实体类的全名（包括命名空间）。

                                                        ②、KeysAsString（string）：更改实体的主键。如果它有一个键，则此属性将是主键值。对于复合键，它将包含由,（逗号）分隔的所有键。

                                             因此，你可以实现IDistributedEventHandler<EntityUpdatedEto<EntityEto>>来订阅更新事件。但是，订阅这种通用事件不是一个号办法，

                                             因为你将会在单个处理程序中处理所有实体的更新事件(因为他们都是用相同的Eto，所以时间类型EntityCreatedEto<T>也一样了).

                                             所以，你需要尽量为每个实体定义自己的Eto。


                                             eg: 声明对 Product 实体使用 ProductEto

                                                    public class ProductEto
                                                    {
                                                        public Guid Id { get; set; }
                                                        public string Name { get; set; }
                                                        public float Price { get; set; }
                                                    }
                                            然后使用 AbpDistributedEntityEventOptions 选项将 Product 类映射到 ProductEto

                                                    Configure<AbpDistributedEntityEventOptions>(options =>
                                                    {
                                                        options.AutoEventSelectors.Add<Product>();
                                                        options.EtoMappings.Add<Product, ProductEto>();  // 在模块类中配置实体到Eto的映射
                                                    });

                                                在这个例子中：
                                                    
                                                      添加选择器以允许发布Product实体的创建、更新和删除事件。

                                                      配置为使用ProductEto作为为Product相关事件发布的事件传输对象。
                                                     
                                            分布式事件系统使用 "对象映射系统"将 Product 实体对象映射到 ProductEto对象。(所以，你需要配置AutoMapper映射文档！！！)
                    */
    </script>
  </body>
</html>